package cn.cheegon.blog.common.security.jwt;

import cn.hutool.core.collection.CollUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
 * @Desc: token 工具类
 * @Author: cheegon
 * @Date: Create in 2024/6/7  下午2:32
 */
@Slf4j
public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);

    private static final String CLAIM_KEY_USERNAME = "user_name";

    @Value("${jwt.expire_time}")
    private Long expireTime;

    @Value("${jwt.secret}")
    private String tokenSecret;

    @Value("${jwt.issuer}")
    private String issuer;


    /**
     * 签名生成
     *
     * @param user
     * @return
     */
    public String sign(UserDetails user) {
        return sign(user, null);
    }

    public String sign(UserDetails user, Map<String, String> customizeClaims) {
        Map<String, String> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, user.getUsername());
        if (CollUtil.isNotEmpty(customizeClaims)) {
            claims.putAll(customizeClaims);
        }
        return generateToken(claims);
    }

    private String generateToken(Map<String, String> claims) {
        JWTCreator.Builder builder = JWT.create();
        claims.forEach(builder::withClaim);
        log.info("tokenSecret:" + tokenSecret);
        return builder
                .withIssuer(issuer)
                .withExpiresAt(generateExpirationDate())
                .sign(Algorithm.HMAC256(tokenSecret));// 使用了HMAC256加密算法。
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Map<String, Claim> claims = getClaimsFromToken(token);
            username = claims.get(CLAIM_KEY_USERNAME).asString();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 从token中获取JWT中的负载
     *
     * @param token
     * @return
     */
    public Map<String, Claim> getClaimsFromToken(String token) {
        try {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenSecret)).withIssuer(issuer).build();
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            return decodedJWT.getClaims();
        } catch (JWTVerificationException e) {
            return null;
        }
    }

    public String getValueFromToken(String token, String key) {
        String value = null;
        try {
            Map<String, Claim> claims = getClaimsFromToken(token);
            value = claims.get(key).asString();
        } catch (Exception e) {
            value = null;
        }
        return value;
    }

    /**
     * 生成token的过期时间
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expireTime * 1000);
    }

    /**
     * 签名验证
     *
     * @param token
     * @return
     */
    public boolean verify(String token) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSecret)).withIssuer(issuer).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return Optional.ofNullable(username).isPresent() && username.equals(userDetails.getUsername());
    }

    /**
     * 管理员认证
     *
     * @param token
     * @return
     */
    public boolean adminVerify(String token) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSecret)).withIssuer(issuer).build();
            DecodedJWT jwt = verifier.verify(token);
            if ("1".equals(jwt.getClaim("userType").asString())) {
                return true;
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }

}